/*	Renegade Scripts.dll
	Main loading code
	Copyright 2007 Datalore, Jonathan Wilson, Whitedragon(MDB)

	This file is part of the Renegade scripts.dll
	The Renegade scripts.dll is free software; you can redistribute it and/or modify it under
	the terms of the GNU General Public License as published by the Free
	Software Foundation; either version 2, or (at your option) any later
	version. See the file COPYING for more details.
	In addition, an exemption is given to allow Run Time Dynamic Linking of this code with any closed source module that does not contain code covered by this licence.
	Only the source code to the module(s) containing the licenced code has to be released.
*/
#ifdef WIN32
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#endif
#include "scripts.h"
#include "engine.h"
#include "gmmain.h"
#ifndef WIN32
#include <dlfcn.h>
#include <time.h>
#endif
#ifdef WIN32
#define SCRIPTSAPI __declspec(dllexport)
#else
#define SCRIPTSAPI
#endif
typedef void (*srdf) (rdf);
typedef void (*ds) (ScriptClass *scr);
typedef ScriptClass *(*cs) (const char *);
typedef int (*gsc) ();
typedef char *(*gsn) (int);
typedef char *(*gspd) (int);
typedef bool (*ssc) (ScriptCommandsClass *);
#ifdef WIN32
HINSTANCE wwscripts;
#endif
cs CreateScript;
ds DestroyScript;
gsc GetScriptCount;
gsn GetScriptName;
gspd GetScriptParamDescription;
srdf SetRequestDestroyFunc;
unsigned int OldCount;
ScriptCommandsClass Commands;
ssc SetScriptCommands;
#ifdef WIN32
HMODULE bhs;
int __cdecl __CxxSetUnhandledExceptionFilter(void);
FARPROC GetProcAddressCheck(HMODULE hModule,LPCSTR lpProcName)
{
	FARPROC x = GetProcAddress(hModule,lpProcName);
	if (!x)
	{
		MessageBox(NULL,"Error getting function address from bhs.dll",lpProcName,MB_OK|MB_ICONEXCLAMATION);
	}
	return x;
}
#define Address GetProcAddressCheck
#else
#define Address dlsym
void *bhs;
#endif
void LoadScopes();
void FreeScopes();
void DestroyExpVehFacClass();
extern "C"
{
#ifdef WIN32
BOOL SCRIPTSAPI __stdcall DllMain(HINSTANCE hinstDLL,
						DWORD	ul_reason_for_call,
						LPVOID	lpReserved
					)
{
	int LastError;
	switch (ul_reason_for_call)
	{
		case DLL_PROCESS_ATTACH:
			DisableThreadLibraryCalls(hinstDLL);
			if (Exe == 6)
			{
				InitEngine();
			}
			if ((!Exe) || (Exe == 1))
			{
				InitEngineSSGM();
				SSGM_Primary_Load();
				if (GetFileAttributes("shaders.dll") == 0xFFFFFFFF)
				{
					FILE *f = fopen("dllload.txt","at");
					if (f)
					{
						fprintf(f,"[shaders.dll] Module not found, unable to continue.\n");
						fclose(f);
					}
					MessageBox(NULL,"shaders.dll was not found. Are you sure you installed scripts.dll correctly?","Error",MB_OK|MB_ICONEXCLAMATION);
					ExitProcess(1);
				}
				if (GetFileAttributes("d3d8.dll") == 0xFFFFFFFF)
				{
					FILE *f = fopen("dllload.txt","at");
					if (f)
					{
						fprintf(f,"[d3d8.dll] Module not found, unable to continue.\n");
						fclose(f);
					}
					MessageBox(NULL,"d3d8.dll was not found. Are you sure you installed scripts.dll correctly?","Error",MB_OK|MB_ICONEXCLAMATION);
					ExitProcess(1);
				}
				if (GetFileAttributes("bhs.dll") == 0xFFFFFFFF)
				{
					FILE *f = fopen("dllload.txt","at");
					if (f)
					{
						fprintf(f,"[bhs.dll] Module not found, unable to continue.\n");
						fclose(f);
					}
					MessageBox(NULL,"bhs.dll was not found. Are you sure you installed scripts.dll correctly?","Error",MB_OK|MB_ICONEXCLAMATION);
					ExitProcess(1);
				}
				bhs = LoadLibrary("bhs.dll");
				LastError = GetLastError();
				if (!bhs)
				{
					FILE *f = fopen("dllload.txt","at");
					if (f)
					{
						char *errorMessage = new char[2048]; //Ugly, but whatever.
						FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM,NULL,LastError,0,errorMessage,2048,NULL);
						fprintf(f,"[bhs.dll] Failed to load, error %d. %s\n",LastError,errorMessage);
						delete[] errorMessage;
						fclose(f);
					}
					MessageBox(NULL,"Unfortunately, there was an error loading bhs.dll. Please report this bug!","Error",MB_OK|MB_ICONEXCLAMATION);
					ExitProcess(1);
				}
			}
			if (GetFileAttributes("scripts2.dll") == 0xFFFFFFFF)
			{
				FILE *f = fopen("dllload.txt","at");
				if (f)
				{
					fprintf(f,"[scripts2.dll] Module not found, unable to continue.\n");
					fclose(f);
				}
				MessageBox(NULL,"scripts2.dll was not found. Are you sure you installed scripts.dll correctly?","Error",MB_OK|MB_ICONEXCLAMATION);
				ExitProcess(1);
			}
			wwscripts = LoadLibrary("scripts2.dll");
			LastError = GetLastError();
			if (wwscripts)
			{
				CreateScript = (cs) GetProcAddress(wwscripts,"Create_Script");
				DestroyScript = (ds) GetProcAddress(wwscripts,"Destroy_Script");
				GetScriptCount = (gsc) GetProcAddress(wwscripts,"Get_Script_Count");
				GetScriptName = (gsn) GetProcAddress(wwscripts,"Get_Script_Name");
				GetScriptParamDescription = (gspd) GetProcAddress(wwscripts,"Get_Script_Param_Description");
				SetScriptCommands = (ssc) GetProcAddress(wwscripts,"Set_Script_Commands");
				SetRequestDestroyFunc = (srdf) GetProcAddress(wwscripts,"Set_Request_Destroy_Func");
				OldCount = (GetScriptCount) ();
			}
			else
			{
				FILE *f = fopen("dllload.txt","at");
				if (f)
				{
					char *errorMessage = new char[2048]; //Ugly, but whatever.
					FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM,NULL,LastError,0,errorMessage,2048,NULL);
					fprintf(f,"[scripts2.dll] Failed to load, error %d. %s\n",LastError,errorMessage);
					delete[] errorMessage;
					fclose(f);
				}
				MessageBox(NULL,"Unfortunately, there was an error loading scripts2.dll. Please report this bug!","Error",MB_OK|MB_ICONEXCLAMATION);
				ExitProcess(1);
			}
			break;
		case DLL_PROCESS_DETACH:
			DestroyEngineMath();
			FreeScopes();
			DestroyExpVehFacClass();
			FreeLibrary(wwscripts);
			SSGM_Unload();
#if DEBUG
			m_dumpMemoryReport("memreport_scripts.log",false);
#endif
			break;
	}
	return TRUE;
}
#endif

ScriptClass SCRIPTSAPI *Create_Script(const char *ScriptName) {
	if (!ScriptName) {
		return 0;
	}
	ScriptClass *scr = 0;
	if (!Data->Plugins.empty()) {
		std::vector<PluginInfo*>::const_iterator it;
		for (it = Data->Plugins.begin();it != Data->Plugins.end(); ++it) {
			if ((*it)->Type) {
				if ((*it)->CreateScriptHandle) {
					scr = (*it)->CreateScriptHandle(ScriptName);
					if (scr) {
						return scr;
					}
				}
			}
		}
	}
	if (!stricmp(ScriptName,"M00_CNC_Crate") && Settings->EnableNewCrates) {
		return 0;
	}

	scr = ScriptRegistrar::CreateScript(ScriptName);
	if (scr) {
		return scr;
	}
	return (CreateScript) (ScriptName);
}

void SCRIPTSAPI Destroy_Script(ScriptClass *scr)
{
	if (scr)
	{
		delete scr;
	}
}

unsigned int SCRIPTSAPI Get_Script_Count()
{
	int sn = 0;
	sn = ScriptRegistrar::Count();
	return (GetScriptCount) () + sn;
}

const char SCRIPTSAPI *Get_Script_Name(unsigned int Number)
{
	if (Number < OldCount)
	{
		return (GetScriptName) (Number);
	}
	int n = Number - OldCount;
	return ScriptRegistrar::GetScriptFactory(n)->GetName();
}

const char SCRIPTSAPI *Get_Script_Param_Description(unsigned int Number)
{
	if (Number < OldCount)
	{
		return (GetScriptParamDescription) (Number);
	}
	int n = Number - OldCount;
	return ScriptRegistrar::GetScriptFactory(n)->GetParamDescription();
}

bool SCRIPTSAPI Set_Script_Commands(ScriptCommandsClass *ScriptCommands)
{
	Commands = *ScriptCommands;
	if ((Commands->version1 != 816) || (Commands->version2 != 174)) //if these dont match it means the ScriptCommands dont match with what is expected and the DLL cant work with whatever client is trying to use it
	{
		return false;
	}
	Commands->Enable_Stealth = (_Enable_Stealth)Address(bhs,"New_Enable_Stealth");
	Commands->Create_Explosion = (_Create_Explosion)Address(bhs,"New_Create_Explosion");
	Commands->Create_Explosion_At_Bone = (_Create_Explosion_At_Bone)Address(bhs,"New_Create_Explosion_At_Bone");
	Commands->Set_Fog_Enable = (_Set_Fog_Enable)Address(bhs,"New_Set_Fog_Enable");
	Commands->Set_Fog_Range = (_Set_Fog_Range)Address(bhs,"New_Set_Fog_Range");
	Commands->Set_War_Blitz = (_Set_War_Blitz)Address(bhs,"New_Set_War_Blitz");
	Commands->Fade_Background_Music = (_Fade_Background_Music)Address(bhs,"New_Fade_Background_Music");
	Commands->Set_Background_Music = (_Set_Background_Music)Address(bhs,"New_Set_Background_Music");
	Commands->Stop_Background_Music = (_Stop_Background_Music)Address(bhs,"New_Stop_Background_Music");
	Commands->Create_Sound = (_Create_Sound)Address(bhs,"New_Create_Sound");
	Commands->Create_2D_Sound = (_Create_2D_Sound)Address(bhs,"New_Create_2D_Sound");
	Commands->Create_2D_WAV_Sound = (_Create_2D_WAV_Sound)Address(bhs,"New_Create_2D_WAV_Sound");
	Commands->Create_3D_WAV_Sound_At_Bone = (_Create_3D_WAV_Sound_At_Bone)Address(bhs,"New_Create_3D_WAV_Sound_At_Bone");
	Commands->Create_3D_Sound_At_Bone = (_Create_3D_Sound_At_Bone)Address(bhs,"New_Create_3D_Sound_At_Bone");
	Commands->Play_Building_Announcement = (_Play_Building_Announcement)Address(bhs,"New_Play_Building_Announcement");
	Commands->Clear_Weapons = (_Clear_Weapons)Address(bhs,"New_Clear_Weapons");
	Commands->Enable_Vehicle_Transitions = (_Enable_Vehicle_Transitions)Address(bhs,"New_Enable_Vehicle_Transitions");
	Commands->Set_Player_Type = (_Set_Player_Type)Address(bhs,"New_Set_Player_Type");
	Commands->Set_Screen_Fade_Color = (_Set_Screen_Fade_Color)Address(bhs,"New_Set_Screen_Fade_Color");
	Commands->Set_Screen_Fade_Opacity = (_Set_Screen_Fade_Opacity)Address(bhs,"New_Set_Screen_Fade_Opacity");
	Commands->Set_Display_Color = (_Set_Display_Color)Address(bhs,"New_Set_Display_Color");
	Commands->Display_Text = (_Display_Text)Address(bhs,"New_Display_Text");
	Commands->Display_Float = (_Display_Float)Address(bhs,"New_Display_Float");
	Commands->Display_Int = (_Display_Int)Address(bhs,"New_Display_Int");
	Commands->Select_Weapon = (_Select_Weapon)Address(bhs,"New_Select_Weapon");
	Commands->Shake_Camera = (_Shake_Camera)Address(bhs,"New_Shake_Camera");
	Commands->Set_Model = (_Set_Model)Address(bhs,"New_Set_Model");
	Enable_Stealth_Player = (_Enable_Stealth_Player)Address(bhs,"New_Enable_Stealth_Player");
	Set_Fog_Enable_Player = (_Set_Fog_Enable_Player)Address(bhs,"New_Set_Fog_Enable_Player");
	Set_Fog_Range_Player = (_Set_Fog_Range_Player)Address(bhs,"New_Set_Fog_Range_Player");
	Set_Background_Music_Player = (_Set_Background_Music_Player)Address(bhs,"New_Set_Background_Music_Player");
	Fade_Background_Music_Player = (_Fade_Background_Music_Player)Address(bhs,"New_Fade_Background_Music_Player");
	Stop_Background_Music_Player = (_Stop_Background_Music_Player)Address(bhs,"New_Stop_Background_Music_Player");
	Enable_Radar_Player = (_Enable_Radar_Player)Address(bhs,"New_Enable_Radar_Player");
	Display_GDI_Player_Terminal_Player = (_Display_GDI_Player_Terminal_Player)Address(bhs,"New_Display_GDI_Player_Terminal_Player");
	Display_NOD_Player_Terminal_Player = (_Display_NOD_Player_Terminal_Player)Address(bhs,"New_Display_NOD_Player_Terminal_Player");
	Set_Screen_Fade_Color_Player = (_Set_Screen_Fade_Color_Player)Address(bhs,"New_Set_Screen_Fade_Color_Player");
	Set_Screen_Fade_Opacity_Player = (_Set_Screen_Fade_Opacity_Player)Address(bhs,"New_Set_Screen_Fade_Opacity_Player");
	Force_Camera_Look_Player = (_Force_Camera_Look_Player)Address(bhs,"New_Force_Camera_Look_Player");
	Enable_HUD_Player = (_Enable_HUD_Player)Address(bhs,"New_Enable_HUD_Player");
	Create_Sound_Player = (_Create_Sound_Player)Address(bhs,"New_Create_Sound_Player");
	Create_2D_Sound_Player = (_Create_2D_Sound_Player)Address(bhs,"New_Create_2D_Sound_Player");
	Create_2D_WAV_Sound_Player = (_Create_2D_WAV_Sound_Player)Address(bhs,"New_Create_2D_WAV_Sound_Player");
	Create_3D_WAV_Sound_At_Bone_Player = (_Create_3D_WAV_Sound_At_Bone_Player)Address(bhs,"New_Create_3D_WAV_Sound_At_Bone_Player");
	Create_3D_Sound_At_Bone_Player = (_Create_3D_Sound_At_Bone_Player)Address(bhs,"New_Create_3D_Sound_At_Bone_Player");
	Set_Display_Color_Player = (_Set_Display_Color_Player)Address(bhs,"New_Set_Display_Color_Player");
	Display_Text_Player = (_Display_Text_Player)Address(bhs,"New_Display_Text_Player");
	Display_Int_Player = (_Display_Int_Player)Address(bhs,"New_Display_Int_Player");
	Display_Float_Player = (_Display_Float_Player)Address(bhs,"New_Display_Float_Player");
	Commands->Set_Obj_Radar_Blip_Shape = (_Set_Obj_Radar_Blip_Shape)Address(bhs,"New_Set_Obj_Radar_Blip_Shape");
	Commands->Set_Obj_Radar_Blip_Color = (_Set_Obj_Radar_Blip_Color)Address(bhs,"New_Set_Obj_Radar_Blip_Color");
	Set_Obj_Radar_Blip_Shape_Player = (_Set_Obj_Radar_Blip_Shape_Player)Address(bhs,"New_Set_Obj_Radar_Blip_Shape_Player");
	Set_Obj_Radar_Blip_Color_Player = (_Set_Obj_Radar_Blip_Color_Player)Address(bhs,"New_Set_Obj_Radar_Blip_Color_Player");
	AddObjectCreateHook = (aoch)Address(bhs,"NewAddObjectCreateHook");
	RemoveObjectCreateHook = (roch)Address(bhs,"NewRemoveObjectCreateHook");
	AddKeyHook = (akh)Address(bhs,"AddKeyHook");
	RemoveKeyHook = (rkh)Address(bhs,"RemoveKeyHook");
	Set_Scope = (ss)Address(bhs,"Set_Scope");
	Set_HUD_Texture = (sh)Address(bhs,"Set_HUD_Texture");
	AddChatHook = (ach)Address(bhs,"AddChatHook");
	AddHostHook = (ahh)Address(bhs,"AddHostHook");
	AddLoadLevelHook = (allh)Address(bhs,"AddLoadLevelHook");
	AddGameOverHook = (allh)Address(bhs,"AddGameOverHook");
	AddPlayerJoinHook = (apjh)Address(bhs,"AddPlayerJoinHook");
	GetCurrentMusicTrack = (gcmt)Address(bhs,"GetCurrentMusicTrack");
	Set_Info_Texture = (sit)Address(bhs,"Set_Info_Texture");
	Clear_Info_Texture = (cit)Address(bhs,"Clear_Info_Texture");
	Set_Vehicle_Limit = (svl)Address(bhs,"Set_Vehicle_Limit");
	Get_Vehicle_Limit = (gvl)Address(bhs,"Get_Vehicle_Limit");
	Send_Message = (sm)Address(bhs,"Send_Message");
	Send_Message_Player = (smp)Address(bhs,"Send_Message_Player");
	Commands->Display_Health_Bar = (_Display_Health_Bar)Address(bhs,"New_Display_Health_Bar");
	AddVersionHook = (avh)Address(bhs,"AddVersionHook");
	Set_Wireframe_Mode = (sw)Address(bhs,"Set_Wireframe_Mode");
	Commands->Disable_All_Collisions = (_Disable_All_Collisions)Address(bhs,"New_Disable_All_Collisions");
	Commands->Disable_Physical_Collisions = (_Disable_Physical_Collisions)Address(bhs,"New_Disable_Physical_Collisions");
	Commands->Enable_Collisions = (_Enable_Collisions)Address(bhs,"New_Enable_Collisions");
	Load_New_HUD_INI = (lnhi)Address(bhs,"Load_New_HUD_INI");
	Remove_Weapon = (rw)Address(bhs,"Remove_Weapon");
	Update_PT_Data = (upd)Address(bhs,"Update_PT_Data");
	Change_Radar_Map = (crm)Address(bhs,"Change_Radar_Map");
	AddPowerupPurchaseHook = (aph)Address(bhs,"AddPowerupPurchaseHook");
	AddVehiclePurchaseHook = (aph)Address(bhs,"AddVehiclePurchaseHook");
	AddCharacterPurchaseHook = (aph)Address(bhs,"AddCharacterPurchaseHook");
	AddPowerupPurchaseMonHook = (apmh)Address(bhs,"AddPowerupPurchaseMonHook");
	AddVehiclePurchaseMonHook = (apmh)Address(bhs,"AddVehiclePurchaseMonHook");
	AddCharacterPurchaseMonHook = (apmh)Address(bhs,"AddCharacterPurchaseMonHook");
	RemovePowerupPurchaseHook = (rph)Address(bhs,"RemovePowerupPurchaseHook");
	RemoveVehiclePurchaseHook = (rph)Address(bhs,"RemoveVehiclePurchaseHook");
	RemoveCharacterPurchaseHook = (rph)Address(bhs,"RemoveCharacterPurchaseHook");
	RemovePowerupPurchaseMonHook = (rph)Address(bhs,"RemovePowerupPurchaseMonHook");
	RemoveVehiclePurchaseMonHook = (rph)Address(bhs,"RemoveVehiclePurchaseMonHook");
	RemoveCharacterPurchaseMonHook = (rph)Address(bhs,"RemoveCharacterPurchaseMonHook");
	Get_Build_Time_Multiplier = (gbm)Address(bhs,"Get_Build_Time_Multiplier");
	Set_Currently_Building = (scb)Address(bhs,"Set_Currently_Building");
	Is_Currently_Building = (icb)Address(bhs,"Is_Currently_Building");
	AddConsoleOutputHook = (acoh)Address(bhs,"AddConsoleOutputHook");
	AddCRCHook = (acrch)Address(bhs,"AddCRCHook");
	AddDataHook = (adh)Address(bhs,"AddDataHook");
	Set_Reticle_Texture1 = (srt)Address(bhs,"Set_Reticle_Texture1");
	Set_Reticle_Texture2 = (srt)Address(bhs,"Set_Reticle_Texture2");
	Set_Fog_Color = (sfc)Address(bhs,"New_Set_Fog_Color");
	Set_Fog_Color_Player = (sfcp)Address(bhs,"Set_Fog_Color_Player");
	Set_Fog_Mode = (sfm)Address(bhs,"New_Set_Fog_Mode");
	Set_Fog_Mode_Player = (sfmp)Address(bhs,"Set_Fog_Mode_Player");
	Set_Shader_Number = (ssn)Address(bhs,"Set_Shader_Number");
	Send_HUD_Number = (shn)Address(bhs,"SendHUDNumber");
	Set_Fog_Density = (sfd)Address(bhs,"New_Set_Fog_Density");
	Set_Fog_Density_Player = (sfdp)Address(bhs,"Set_Fog_Density_Player");
	Change_Time_Remaining = (ctr)Address(bhs,"New_Change_Time_Remaining");
	Change_Time_Limit = (ctl)Address(bhs,"New_Change_Time_Limit");
	Display_GDI_Sidebar = (dps)Address(bhs,"Display_GDI_Sidebar");
	Display_NOD_Sidebar = (dps)Address(bhs,"Display_NOD_Sidebar");
	Display_Security_Dialog = (dps)Address(bhs,"Display_Security_Dialog");
	AddPlayerLeaveHook = (aplh)Address(bhs,"AddPlayerLeaveHook");
	GetExplosionObj = (geo)Address(bhs,"GetExplosionObj");
	gbhsv GetBHSVersion = (gbhsv)Address(bhs,"GetBHSVersion");
	if (GetBHSVersion() != BHS_VERSION) {
		Console_Output("Fatal Error: SSGM v%s requires a bhs.dll version of %f. You are running %f.",SSGMVersion,BHS_VERSION,GetBHSVersion());
		return false;
	}
	LoadScopes();

	SSGM_Secondary_Load();
	if (!Data->Plugins.empty()) {
		std::vector<PluginInfo*>::const_iterator it;
		for (it = Data->Plugins.begin();it != Data->Plugins.end(); ++it) {
			if ((*it)->Type) {
				ssc PluginCommands = (ssc)(*it)->Get_Address("Set_Script_Commands");
				if (PluginCommands) {
					PluginCommands(ScriptCommands);
				}
			}
		}
	}
	return (SetScriptCommands) (ScriptCommands);
}

void SCRIPTSAPI Set_Request_Destroy_Func(rdf Func) {
	ScriptImpClass::Set_Request_Destroy_Func(Func);
	if (!Data->Plugins.empty()) {
		std::vector<PluginInfo*>::const_iterator it;
		for (it = Data->Plugins.begin();it != Data->Plugins.end(); ++it) {
			if ((*it)->Type) {
				srdf PluginSRDF = (srdf)(*it)->Get_Address("Set_Request_Destroy_Func");
				if (PluginSRDF) {
					PluginSRDF(Func);
				}
			}
		}
	}
	(SetRequestDestroyFunc) (Func);
}

#ifndef WIN32
/**
 *Scripts.so module patch.
 *
 *Written by Datalore.
 *Original idea by Mac.
 */

// Variable to keep track of patching
int scripts_patched = 0;

// Functions to call back to the original binary
ScriptClass *ORG_Create_Script(const char *ScriptName)
{
	__asm__(
		".byte 0xc9;"						// leave
#ifdef RH8
		".byte 0xB9; .byte 0xbb; .byte 0x9e; .byte 0x36; .byte 0x08;"// add absolute target to ecx
#else
		".byte 0xB9; .byte 0x23; .byte 0x8d; .byte 0x3b; .byte 0x08;"	// add absolute target to ecx
#endif
		".byte 0x83; .byte 0xec; .byte 0x18;"			// original code
		".byte 0xff; .byte 0x74; .byte 0x24; .byte 0x1c;"	// original code
		".byte 0xff; .byte 0xe1;"			// jmp ecx
		);
	return 0; //silence compiler warning
}

void ORG_Destroy_Script(ScriptClass *scr)
{
	__asm__(
		".byte 0xc9;"
#ifdef RH8
		".byte 0xB9; .byte 0xcb; .byte 0x9e; .byte 0x36; .byte 0x08;"
#else
		".byte 0xB9; .byte 0x33; .byte 0x8d; .byte 0x3b; .byte 0x08;"
#endif
		".byte 0x83; .byte 0xec; .byte 0x0c;"
		".byte 0x8b; .byte 0x54; .byte 0x24; .byte 0x10;"
		".byte 0xff; .byte 0xe1;"
		);
}

unsigned int ORG_Get_Script_Count()
{
	return OldCount;
}

char *ORG_Get_Script_Name(unsigned int Number)
{
	__asm__(
		".byte 0xc9;"
#ifdef RH8
		".byte 0xB9; .byte 0x05; .byte 0x9f; .byte 0x36; .byte 0x08;"
#else
		".byte 0xB9; .byte 0x7b; .byte 0x8d; .byte 0x3b; .byte 0x08;"
#endif
		".byte 0x83; .byte 0xec; .byte 0x18;"
		".byte 0xff; .byte 0x74; .byte 0x24; .byte 0x1c;"
		".byte 0xff; .byte 0xe1;"
		);
	return 0; //silence compiler warning
}

char *ORG_Get_Script_Param_Description(unsigned int Number)
{
	__asm__(
		".byte 0xc9;"
#ifdef RH8
		".byte 0xB9; .byte 0x2f; .byte 0x9f; .byte 0x36; .byte 0x08;"
#else
		".byte 0xB9; .byte 0x8b; .byte 0x8d; .byte 0x3b; .byte 0x08;"
#endif
		".byte 0x83; .byte 0xec; .byte 0x18;"
		".byte 0xff; .byte 0x74; .byte 0x24; .byte 0x1c;"
		".byte 0xff; .byte 0xe1;"
		);
	return 0; //silence compiler warning
}

bool ORG_Set_Script_Commands(ScriptCommandsClass *ScriptCommands)
{
	__asm__(
		".byte 0xc9;"
#ifdef RH8
		".byte 0xB9; .byte 0x59; .byte 0x9f; .byte 0x36; .byte 0x08;"
#else
		".byte 0xB9; .byte 0xdb; .byte 0x8d; .byte 0x3b; .byte 0x08;"
#endif
		".byte 0x83; .byte 0xec; .byte 0x0c;"
		".byte 0x8b; .byte 0x44; .byte 0x24; .byte 0x10;"
		".byte 0xff; .byte 0xe1;"
		);
	return 0; //silence compiler warning
}

rdf *org;
void ORG_Set_Request_Destroy_Func(rdf Func)
{
#ifdef RH8
	org = (rdf *)0x08651B4C;
#else
	org = (rdf *)0x087227A0;
#endif
	org = &Func;
}

// Simple helper function to patch in a jmp
void patch_in_jmp(const unsigned int fixed_address,void *jmp_to)
{
	char *memory = (char*)fixed_address;
	*memory = 0xe9; // jmp instruction
	unsigned int *address = (unsigned int*)(fixed_address + 1);
	*address = (unsigned int)jmp_to - fixed_address - 5; // relative address to jmp to
}

// The GLIBC function we hacked (ctime)
gsc sc;
typedef void (*init) (int exetype);
char *CXIME(const time_t *tp)
{
	if (!scripts_patched)
	{
		scripts_patched = 1;
		init initbhs;
#ifdef RH8
		bhs = dlopen("./bhs8.so",RTLD_NOW);
		Exe = 3;
#else
		bhs = dlopen("./bhs.so",RTLD_NOW);
		Exe = 2;
#endif
#ifdef RH8
		sc = (gsc)(0x08369EF2);
#else
		sc = (gsc)(0x083B8D68);
#endif
		InitEngine();
		InitEngineSSGM();
		if (bhs)
		{
			initbhs = (init)dlsym(bhs,"initlinux");
#ifdef RH8
			initbhs(3);
#else
			initbhs(2);
#endif
		}
		else
		{
			printf("%s\n",dlerror());
			printf("bhs.so not found.\n");
			exit(1);
		}
		printf("Linux Scripts Patch enabled.\n- Initializing scripts.so patch!\n");
		// fill in function addresses
		CreateScript = (cs)((unsigned int)&ORG_Create_Script);
		DestroyScript = (ds)((unsigned int)&ORG_Destroy_Script);
		GetScriptCount = (gsc)((unsigned int)&ORG_Get_Script_Count);
		GetScriptName = (gsn)((unsigned int)&ORG_Get_Script_Name);
		GetScriptParamDescription = (gspd)((unsigned int)&ORG_Get_Script_Param_Description);
		SetScriptCommands = (ssc)((unsigned int)&ORG_Set_Script_Commands);
		SetRequestDestroyFunc = (srdf)((unsigned int)&ORG_Set_Request_Destroy_Func);
		// get the original script count
		OldCount = sc();
		printf("- Original built-in script count: %d\n",OldCount);
		// patch the function entries,so that they jmp to our script functions 
#ifdef RH8
		patch_in_jmp(0x08369EB4,(void*)&Create_Script);
		patch_in_jmp(0x08369EC4,(void*)&Destroy_Script);
		patch_in_jmp(0x08369EF2,(void*)&Get_Script_Count);
		patch_in_jmp(0x08369EFE,(void*)&Get_Script_Name);
		patch_in_jmp(0x08369F28,(void*)&Get_Script_Param_Description);
		patch_in_jmp(0x08369F52,(void*)&Set_Script_Commands);
		patch_in_jmp(0x08369FB2,(void*)&Set_Request_Destroy_Func);
#else
		patch_in_jmp(0x083B8D1C,(void*)&Create_Script);
		patch_in_jmp(0x083B8D2C,(void*)&Destroy_Script);
		patch_in_jmp(0x083B8D68,(void*)&Get_Script_Count);
		patch_in_jmp(0x083B8D74,(void*)&Get_Script_Name);
		patch_in_jmp(0x083B8DA4,(void*)&Get_Script_Param_Description);
		patch_in_jmp(0x083B8DD4,(void*)&Set_Script_Commands);
		patch_in_jmp(0x083B8E30,(void*)&Set_Request_Destroy_Func);
#endif
		// last output
		printf("- Total script count: %d\n",Get_Script_Count());
		printf("- Linux Scripts Patch succesfully applied\n");
		SSGM_Primary_Load();
	}
	return ctime(tp);
}
#endif
} //extern "C"
